package com.google.com.p.joat_wordfilter;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Logger;

import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;

/**
 * 
 * Class that filters out bad words from strings
 *
 * This uses a yml file of bad words.  It will be of the format:
 * 
 badwords:
  fatal:
  - reallyBadWord1
  - reallyBadWord2
  nearfatal:
  - badWord1
  - badWord2

 */
public class BadWordFilter {

	private Logger _log;
	private List<String> _fatalWords;
	private List<String> _nearFatalWords;
	private FileConfiguration _conf;
	private String _folderName;
	private boolean _isDirty = false;
	private HashMap<String,Integer> badWords = new HashMap<String,Integer>();
	
	/**
	 * Constructor
	 * 
	 * @param p Logger for logging messages, and original message, if filtered
	 * @param folderName where to look for badwords.yml
	 */
	public BadWordFilter(Logger p, String folderName)
	{
		this._log = p;
    	this._folderName = folderName;
    	reloadWords();
	}

	/**
	 * reload the word file
	 */
    public void reloadWords() {
    	
		File confFile = new File(this._folderName, "badwords.yml");
		_log.info("Loading words from "+this._folderName+"\\"+"badwords.yml");
		_conf = YamlConfiguration.loadConfiguration(confFile);
		this._fatalWords = _conf.getStringList("badwords.fatal");
		this._nearFatalWords = _conf.getStringList("badwords.nearfatal");
		if ( this._fatalWords == null || this._nearFatalWords == null )
			_log.warning("Failed to load words from file");
		else
		{
			_log.info("BadWordFilter loaded "+this._fatalWords.size()+" fatal and "+this._nearFatalWords.size()+" near fatal words");
			for ( int i = 0; i < this._nearFatalWords.size(); i++ )
			{
				badWords.put(this._nearFatalWords.get(i),1);
			}
		}
	}

    /**
     * save the list in memory to disk
     */
	public void saveList()
    {
    	if ( this._isDirty  )
    	{
    		// etc.
    		try {
    			File confFile = new File(this._folderName, "badwords.yml");
    			_conf.save(confFile);
    			this._isDirty = false;
    		} catch (IOException e) {
    			_log.warning("Error saving bad words"+e.toString());
    		}
    	}
    }
	
	/**
	 * add a word to the list of bad words
	 * @param word the word to add
	 * @return true if wasn't already in the list
	 */
	public boolean addWord(String word)
	{
		if ( !this.badWords.containsKey(word))
		{
			this._nearFatalWords.add(word);
			this.badWords.put(word,1);
			this._conf.set("badwords.nearfatal", this._nearFatalWords);
			this._isDirty = true;
		}
		return this._isDirty;
	}

	/**
	 * remove a word from the list
	 * @param word the word to remove
	 * @return true if the word was in the list
	 */
	public boolean removeWord(String word)
	{
		if ( this.badWords.containsKey(word))
		{
			this.badWords.remove(word);
			for ( int i = 0; i > this._nearFatalWords.size(); i++ )
			{
				if ( this._nearFatalWords.get(i) == word )
				{
					this._nearFatalWords.remove(i);
					break;
				}
			}
			this._conf.set("badwords.nearfatal", this._nearFatalWords);
			this._isDirty = true;
		}
		return this._isDirty;
	}
	
	private static String normalize( String _msg)
	{
		String msg = " "+_msg+" ".toLowerCase().replaceAll("[\\_\\-\\+]", " ").replaceAll("\\s\\s+", " ");

		// for w o r d s like that, collapse them
		StringBuilder sb = new StringBuilder();
		boolean foundPattern = false;
		for ( int i = 0; i < msg.length(); i++ )
		{
			if ( foundPattern && i+2 < msg.length() && msg.charAt(i) == ' ' && msg.charAt(i+2) == ' ')
			{
				sb.append(msg.charAt(i+1));
				i = i + 1;
			}
			else if (!foundPattern && i+4 < msg.length() && msg.charAt(i) == ' ' && msg.charAt(i+2) == ' '&& msg.charAt(i+4) == ' ' )
			{
				sb.append(" ");
				sb.append(msg.charAt(i+1));
				i = i + 1;
				foundPattern = true;
			}
			else
			{
				sb.append(msg.charAt(i));
				foundPattern = false;
			}
		}
		return sb.toString();
	
	}
	
	/**
	 * mask out any bad words in the list
	 * 
	 * @param _msg the message to filter
	 * @return a filtered message, or null if it was ok
	 * 
	 */
	public String maskBadWords(String _msg )
	{
		String ret = null;
		String msg = normalize(_msg);
		
		// used to strip everything to look for fatal works, but
		// things like "if u know what i mean" caused problems :o
//		StringBuilder sb = new StringBuilder();
//		for ( int i = 0; i < msg.length(); i++)
//		{
//			if ( msg.charAt(i) >= 'a' && msg.charAt(i) <= 'z')
//				sb.append(msg.charAt(i));
//		}
//		
//		String filter = sb.toString();
		String filter = msg;
		for ( int i = 0; i < this._fatalWords.size(); i++ )
			if ( filter.indexOf(this._fatalWords.get(i)) >= 0 )
			{
				return "f***bomb!";
			}
						
		String [] words = msg.split("\\W"); // split on non-word chars
		for ( int i = 0; i < words.length; i++)
		{
			if ( badWords.containsKey(words[i]))
			{
				String r = ""+words[i].charAt(0)+new String(new char[words[i].length()-1]).replace("\0", "*");
				msg = msg.replace(words[i],r);
				ret = msg;
			}
		}
		return ret;
	}
	
	public static void main(String args[])
	{
		String _msg = "as +_   ++++df    ___ ---- as  a b c d  ";
		String msg = _msg.toLowerCase().replaceAll("[\\_\\-\\+]", " ").replaceAll("\\s\\s+", " ");
		msg = msg.replaceAll(" (\\w) ", "$1 ");
		msg = normalize("a s this is a test of l o n g works that a r e");
		System.out.print(msg);
		BadWordFilter bw = new BadWordFilter(Logger.getLogger("Test"), "C:\\Users\\Public\\workspace\\WordFilter-jmw");
		System.out.println(bw.maskBadWords("fuck you"));
		System.out.println(bw.maskBadWords("fuk you"));
		System.out.println(bw.maskBadWords("f u _+k you"));
		System.out.println(bw.maskBadWords("it this ok?"));
		bw.addWord("ok");
		System.out.println(bw.maskBadWords("it this ok?"));
	}
		
}
